<template>
    <div class="table-wrapper">
        <QueryForm v-if="dynamicQuery" :queryFormItems="queryFormItems ?? []" @onQuerySubmit="onQuerySubmit"></QueryForm>

        <TableHeader
            :controllerUrl="controllerUrl"
            :headerActionTypes="headerActionTypes ?? []"
            :selectCount="selection?.length"
            :defaultExpandAll="defaultExpandAll"
            @onHeaderAction="onHeaderAction"
        >
            <template #append>
                <ShowColumnSet :columns="columnArr" @onShowColumnChange="onShowColumnChange"></ShowColumnSet>
            </template>
        </TableHeader>

        <el-table
            ref="tableRef"
            :data="data"
            v-loading="loading"
            :element-loading-text="elementLoadingText"
            :empty-text="emptyText"
            :height="tableHeight"
            :row-key="rowKey"
            :border="border"
            :stripe="stripe"
            :default-expand-all="defaultExpandAll"
            :expand-row-keys="expandRowKeys"
            @selection-change="onSelectionChange"
            @row-click="onRowClick"
            v-bind="$attrs"
        >
            <TableColumns
                :controllerUrl="controllerUrl"
                :columns="columnArr ?? []"
                :columnActionTypes="columnActionTypes ?? []"
                @onColumnAction="onColumnAction"
            ></TableColumns>
        </el-table>

        <div v-if="props.page" class="table-pagination">
            <el-pagination
                v-if="!$slots['pagination']"
                :currentPage="pagination.currentPage"
                :page-size="pagination.pageSize"
                :page-sizes="[10, 20, 50, 100, 200]"
                background
                layout="prev, pager, next, jumper, ->, sizes, total"
                :total="pagination.total"
                @size-change="onPageSizeChange"
                @current-change="onCurrentPageChange"
            ></el-pagination>
            <slot name="pagination"></slot>
        </div>

        <slot name="form"></slot>
    </div>
</template>

<script setup lang="tsx">
import { QueryFormItem } from '@/types/queryform'
import { Page } from '@/types/type'
import { ElTable } from 'element-plus'
import Sortable from 'sortablejs'
import { getFlatArray } from '@/utils/common'
import { ProTableData } from '@/hooks/interface'
import { ControllerType } from '@/api/common/types'

type ElTableProps = Partial<InstanceType<typeof ElTable>['$props']>

interface Props extends /* @vue-ignore */ ElTableProps {
    table: ProTableData
    data: any
    page: Page
    columns: TableColumnType<any>[]
    queryFormItems: QueryFormItem<any>[]
    headerActionTypes: TableHeaderActionType[]
    columnActionTypes: TableColumnActionType[]
    controllerUrl: ControllerType

    loading: boolean
    border: boolean
    stripe: boolean
    defaultExpandAll: boolean
    dynamicQuery: boolean

    elementLoadingText: string
    rowKey: string
    expandRowKeys: string[]
}
const props = withDefaults(defineProps<Partial<Props>>(), {
    loading: false,
    border: true,
    stripe: true,
    defaultExpandAll: false,
    rowKey: 'id',
    elementLoadingText: 'Loading . . .',
})
const emit = defineEmits<{ onTableAction: [action: TableActionType, params?: any] }>()

const tableRef = ref()

const columnArr = ref(props.columns)
const selection = ref<any[]>()
const pagination = reactive<Page>(
    props.page ?? {
        total: 0,
        currentPage: 1,
        pageSize: 20,
        pageCount: 0,
    },
)

const emptyText = computed(() => (props.loading ? '' : '暂无数据'))

const mainRef = inject<HTMLElement>(MAINHEIGHT)
const { width, height } = useElementSize(mainRef)
const { config } = useConfigStore()
const tableHeight = computed(() => {
    switch (config.size) {
        case 'large':
            return props.page ? height.value - 61 - 61 - 30 : height.value - 61 - 30
        case 'default':
            return props.page ? height.value - 53 - 53 - 30 : height.value - 53 - 30
        case 'small':
            return props.page ? height.value - 45 - 45 - 30 : height.value - 45 - 30
        default:
            break
    }
})

onMounted(() => {
    initDargSort()
})

// 初始化排序
const initDargSort = () => {
    const tbody: HTMLElement | null = document.querySelector('.el-table__body-wrapper tbody')
    if (tbody) {
        Sortable.create(tbody, {
            animation: 300,
            ghostClass: 'sortable-ghost',
            handle: '.drag-handle',
            onEnd: ({ newIndex, oldIndex }: Sortable.SortableEvent) => {
                if (newIndex !== undefined && oldIndex !== undefined && newIndex !== oldIndex) {
                    let data: any[] = []
                    // 如果数据是树形结构则扁平化数据结构
                    if (props.data[0].children !== undefined) {
                        data = getFlatArray(props.data)
                        if (data[oldIndex].parentId !== data[newIndex].parentId) {
                            ElMessage.error('移动位置超出了可移动范围')
                            emit('onTableAction', 'refresh', true)
                            return
                        }
                    } else {
                        data = props.data
                    }
                    const id = data[oldIndex].id
                    const targetId = data[newIndex].id
                    emit('onTableAction', 'dragSort', { id: id, targetId: targetId })
                }
            },
        })
    }
}

const getTableRef = () => {
    if (tableRef.value) return tableRef
}

// 要显示的列改变
const onShowColumnChange = (columns: TableColumnType<any>[]) => {
    columnArr.value = columns
}
// 动态查询提交
const onQuerySubmit = (action: TableActionType, params: any) => {
    emit('onTableAction', action, params)
}
// 行内操作
const onColumnAction = (action: TableColumnActionType, params: any) => {
    emit('onTableAction', action, params)
}
// 表头操作
const onHeaderAction = (action: TableHeaderActionType, params: any) => {
    emit('onTableAction', action, params)
}
// 选择改变
const onSelectionChange = (newSelection: any[]) => {
    selection.value = newSelection
    emit('onTableAction', 'selection-change', newSelection)
}
const onRowClick = (row: any, column: any, event: Event) => {
    emit('onTableAction', 'row-click', row)
}
// 页面大小改变
const onPageSizeChange = (value: number) => {
    emit('onTableAction', 'size-change', value)
}
// 当前页改变
const onCurrentPageChange = (value: number) => {
    emit('onTableAction', 'current-change', value)
}
// 折叠所有
const onExpandOrFoldAll = (boole: boolean) => {
    setExpandOrFoldAll(props.data, boole)
}
// 执行折叠所有
const setExpandOrFoldAll = (children: any[], unfold: boolean) => {
    for (const key in children) {
        tableRef.value?.toggleRowExpansion(children[key], unfold)
        if (children[key].children) {
            setExpandOrFoldAll(children[key].children!, unfold)
        }
    }
}
defineExpose({
    onExpandOrFoldAll,
    getTableRef,
})
</script>

<style lang="scss" scoped>
.table-wrapper {
    width: v-bind(width);
    height: 100%;
    margin: 15px;
    overflow: hidden;

    .table-query-form {
        border: 1px solid var(--el-border-color-lighter);
        border-bottom: none;
        padding: 10px;
    }

    .table-header-action {
        display: flex;
        justify-content: flex-start;
        align-items: center;

        border: 1px solid var(--el-border-color-lighter);
        border-bottom: none;
        padding: 10px;
        overflow: hidden;

        .table-header-right {
            margin-left: auto;
            display: flex;
            justify-content: flex-end;
            align-items: center;
            gap: 12px;
        }
    }

    .table-pagination {
        border: 1px solid var(--el-border-color-lighter);
        border-top: none;
        padding: 10px;
    }
}
</style>
